// Magic Software, Inc.
// http://www.magic-software.com
// Copyright (c) 2000, All Rights Reserved
//
// Source code from Magic Software is supplied under the terms of a license
// agreement and may not be copied or disclosed except in accordance with the
// terms of that agreement.  The various license agreements may be found at
// the Magic Software web site.  This file is subject to the license
//
// FREE SOURCE CODE
// http://www.magic-software.com/License.html/free.pdf

#include "MgcApplication.h"
#include "MgcCommand.h"

using namespace Mgc;

MgcApplication* MgcApplication::ms_pkApplication = 0;
MgcCommand* MgcApplication::ms_pkCommand = 0;
char* MgcApplication::ms_acWindowTitle = 0;
int MgcApplication::ms_iWindowID = 0;
int MgcApplication::ms_iWidth = 0;
int MgcApplication::ms_iHeight = 0;
MgcColor MgcApplication::ms_kBackgroundColor;
MgcRendererPtr MgcApplication::ms_spkRenderer;
MgcCameraPtr MgcApplication::ms_spkCamera;

// for MS Windows and GLUT
#pragma comment(lib,"comctl32.lib")
#pragma comment(lib,"winmm.lib")
#pragma comment(lib,"opengl32.lib")
#pragma comment(lib,"glu32.lib")
#pragma comment(lib,"MgcCore.lib")
#pragma comment(lib,"MgcEngine.lib")

//----------------------------------------------------------------------------
MgcApplication::MgcApplication (char* acWindowTitle, int iWidth,
    int iHeight, const MgcColor& rkBackgroundColor)
{
    assert( ms_pkApplication == 0 );
    ms_pkApplication = this;

    ms_acWindowTitle = acWindowTitle;
    ms_iWidth = iWidth;
    ms_iHeight = iHeight;
    ms_kBackgroundColor = rkBackgroundColor;
}
//----------------------------------------------------------------------------
MgcApplication::~MgcApplication ()
{
    assert( ms_pkApplication != 0 );
    ms_pkApplication = 0;

    delete ms_pkCommand;
}
//----------------------------------------------------------------------------

//----------------------------------------------------------------------------
// application callbacks
//---------------------------------------------------------------------------
bool MgcApplication::OnInitialize ()
{
    ms_spkRenderer->SetBackgroundColor(ms_kBackgroundColor);
    ms_spkRenderer->SetCamera(ms_spkCamera);

    m_bTurretActive = false;
    m_fTrnSpeed = 0.01;
    m_fRotSpeed = 0.01;
    m_bUArrowPressed = false;
    m_bDArrowPressed = false;
    m_bLArrowPressed = false;
    m_bRArrowPressed = false;
    m_bPgUpPressed = false;
    m_bPgDnPressed = false;
    m_bHomePressed = false;
    m_bEndPressed = false;

    m_fLastTime = -1.0;
    m_fAccumulatedTime = 0.0;
    m_fFrameRate = 0.0;
    m_iClicks = 0;
    m_iTimer = 30;
    m_iMaxTimer = 30;

    return true;
}
//---------------------------------------------------------------------------
void MgcApplication::OnTerminate ()
{
    ms_spkRenderer->SetCamera(0);
    ms_spkCamera = 0;
    ms_spkRenderer = 0;
}
//---------------------------------------------------------------------------
void MgcApplication::OnReshape (int, int)
{
}
//---------------------------------------------------------------------------
void MgcApplication::OnDisplay ()
{
    OnIdle();
}
//---------------------------------------------------------------------------
void MgcApplication::OnIdle ()
{
}
//----------------------------------------------------------------------------
void MgcApplication::OnKeyPress (unsigned char ucKey, int, int)
{
    // quit application if the ESCAPE key is pressed
    if ( ucKey == KEY_ESCAPE )
        RequestTermination();
}
//----------------------------------------------------------------------------
void MgcApplication::OnKeyDown (int)
{
}
//----------------------------------------------------------------------------
void MgcApplication::OnKeyUp (int)
{
}
//----------------------------------------------------------------------------
void MgcApplication::OnSpecialKeyPress (int iKey, int, int)
{
    if ( !m_bTurretActive )
        return;

    if ( iKey == KEY_LEFT_ARROW )
    {
        m_bLArrowPressed = true;
        return;
    }

    if ( iKey == KEY_RIGHT_ARROW )
    {
        m_bRArrowPressed = true;
        return;
    }

    if ( iKey == KEY_UP_ARROW )
    {
        m_bUArrowPressed = true;
        return;
    }

    if ( iKey == KEY_DOWN_ARROW )
    {
        m_bDArrowPressed = true;
        return;
    }

    if ( iKey == KEY_PAGE_UP )
    {
        m_bPgUpPressed = true;
        return;
    }

    if ( iKey == KEY_PAGE_DOWN )
    {
        m_bPgDnPressed = true;
        return;
    }

    if ( iKey == KEY_HOME )
    {
        m_bHomePressed = true;
        return;
    }

    if ( iKey == KEY_END )
    {
        m_bEndPressed = true;
        return;
    }
}
//----------------------------------------------------------------------------
void MgcApplication::OnSpecialKeyDown (int iKey)
{
    if ( !m_bTurretActive )
        return;

    if ( iKey == KEY_LEFT_ARROW )
    {
        m_bLArrowPressed = true;
        return;
    }

    if ( iKey == KEY_RIGHT_ARROW )
    {
        m_bRArrowPressed = true;
        return;
    }

    if ( iKey == KEY_UP_ARROW )
    {
        m_bUArrowPressed = true;
        return;
    }

    if ( iKey == KEY_DOWN_ARROW )
    {
        m_bDArrowPressed = true;
        return;
    }

    if ( iKey == KEY_PAGE_UP )
    {
        m_bPgUpPressed = true;
        return;
    }

    if ( iKey == KEY_PAGE_DOWN )
    {
        m_bPgDnPressed = true;
        return;
    }

    if ( iKey == KEY_HOME )
    {
        m_bHomePressed = true;
        return;
    }

    if ( iKey == KEY_END )
    {
        m_bEndPressed = true;
        return;
    }
}
//----------------------------------------------------------------------------
void MgcApplication::OnSpecialKeyUp (int iKey)
{
    if ( !m_bTurretActive )
        return;

    if ( iKey == KEY_LEFT_ARROW )
    {
        m_bLArrowPressed = false;
        return;
    }

    if ( iKey == KEY_RIGHT_ARROW )
    {
        m_bRArrowPressed = false;
        return;
    }

    if ( iKey == KEY_UP_ARROW )
    {
        m_bUArrowPressed = false;
        return;
    }

    if ( iKey == KEY_DOWN_ARROW )
    {
        m_bDArrowPressed = false;
        return;
    }

    if ( iKey == KEY_PAGE_UP )
    {
        m_bPgUpPressed = false;
        return;
    }

    if ( iKey == KEY_PAGE_DOWN )
    {
        m_bPgDnPressed = false;
        return;
    }

    if ( iKey == KEY_HOME )
    {
        m_bHomePressed = false;
        return;
    }

    if ( iKey == KEY_END )
    {
        m_bEndPressed = false;
        return;
    }
}
//----------------------------------------------------------------------------
void MgcApplication::OnMousePress (int, int, int, int)
{
}
//----------------------------------------------------------------------------
void MgcApplication::OnMotion (int, int)
{
}
//----------------------------------------------------------------------------
void MgcApplication::OnPassiveMotion (int, int)
{
}
//----------------------------------------------------------------------------

//----------------------------------------------------------------------------
// turret-based camera motion
//----------------------------------------------------------------------------
void MgcApplication::SetTurretAxes ()
{
    m_akAxis[0] = ms_spkCamera->GetLeft();
    m_akAxis[1] = ms_spkCamera->GetUp();
    m_akAxis[2] = ms_spkCamera->GetDirection();
}
//----------------------------------------------------------------------------
void MgcApplication::SetTurretAxes (const MgcVector3& rkLeft,
    const MgcVector3& rkUp, const MgcVector3& rkDirection)
{
    m_akAxis[0] = rkLeft;
    m_akAxis[1] = rkUp;
    m_akAxis[2] = rkDirection;
}
//----------------------------------------------------------------------------
void MgcApplication::MoveForward ()
{
    MgcVector3 kLoc = ms_spkCamera->GetLocation();
    kLoc += m_fTrnSpeed*m_akAxis[2];
    ms_spkCamera->SetLocation(kLoc);
    ms_spkCamera->Update();
}
//----------------------------------------------------------------------------
void MgcApplication::MoveBackward ()
{
    MgcVector3 kLoc = ms_spkCamera->GetLocation();
    kLoc -= m_fTrnSpeed*m_akAxis[2];
    ms_spkCamera->SetLocation(kLoc);
    ms_spkCamera->Update();
}
//----------------------------------------------------------------------------
void MgcApplication::MoveUp ()
{
    MgcVector3 kLoc = ms_spkCamera->GetLocation();
    kLoc += m_fTrnSpeed*m_akAxis[1];
    ms_spkCamera->SetLocation(kLoc);
    ms_spkCamera->Update();
}
//----------------------------------------------------------------------------
void MgcApplication::MoveDown ()
{
    MgcVector3 kLoc = ms_spkCamera->GetLocation();
    kLoc -= m_fTrnSpeed*m_akAxis[1];
    ms_spkCamera->SetLocation(kLoc);
    ms_spkCamera->Update();
}
//----------------------------------------------------------------------------
void MgcApplication::TurnLeft ()
{
    MgcMatrix3 kIncr;

    kIncr.FromAxisAngle(m_akAxis[1],m_fRotSpeed);
    m_akAxis[0] = kIncr*m_akAxis[0];
    m_akAxis[2] = kIncr*m_akAxis[2];

    MgcVector3 kLeft = kIncr*ms_spkCamera->GetLeft();
    MgcVector3 kUp = kIncr*ms_spkCamera->GetUp();
    MgcVector3 kDirection = kIncr*ms_spkCamera->GetDirection();
    ms_spkCamera->SetAxes(kLeft,kUp,kDirection);
    ms_spkCamera->Update();
}
//----------------------------------------------------------------------------
void MgcApplication::TurnRight ()
{
    MgcMatrix3 kIncr;

    kIncr.FromAxisAngle(m_akAxis[1],-m_fRotSpeed);
    m_akAxis[0] = kIncr*m_akAxis[0];
    m_akAxis[2] = kIncr*m_akAxis[2];

    MgcVector3 kLeft = kIncr*ms_spkCamera->GetLeft();
    MgcVector3 kUp = kIncr*ms_spkCamera->GetUp();
    MgcVector3 kDirection = kIncr*ms_spkCamera->GetDirection();
    ms_spkCamera->SetAxes(kLeft,kUp,kDirection);
    ms_spkCamera->Update();
}
//----------------------------------------------------------------------------
void MgcApplication::LookUp ()
{
    MgcMatrix3 kIncr;

    kIncr.FromAxisAngle(m_akAxis[0],-m_fRotSpeed);

    MgcVector3 kLeft = kIncr*ms_spkCamera->GetLeft();
    MgcVector3 kUp = kIncr*ms_spkCamera->GetUp();
    MgcVector3 kDirection = kIncr*ms_spkCamera->GetDirection();
    ms_spkCamera->SetAxes(kLeft,kUp,kDirection);
    ms_spkCamera->Update();
}
//----------------------------------------------------------------------------
void MgcApplication::LookDown ()
{
    MgcMatrix3 kIncr;

    kIncr.FromAxisAngle(m_akAxis[0],m_fRotSpeed);

    MgcVector3 kLeft = kIncr*ms_spkCamera->GetLeft();
    MgcVector3 kUp = kIncr*ms_spkCamera->GetUp();
    MgcVector3 kDirection = kIncr*ms_spkCamera->GetDirection();
    ms_spkCamera->SetAxes(ms_spkCamera->GetLeft(),kUp,kDirection);
    ms_spkCamera->Update();
}
//----------------------------------------------------------------------------

//----------------------------------------------------------------------------
// performance measurements
//----------------------------------------------------------------------------
void MgcApplication::ResetTime ()
{
    m_fLastTime = -1.0;
}
//---------------------------------------------------------------------------
void MgcApplication::MeasureTime ()
{
    // start performance measurements
    if ( m_fLastTime == -1.0 )
    {
        m_fLastTime = GetTimeInSeconds();
        m_fAccumulatedTime = 0.0;
        m_fFrameRate = 0.0;
        m_iClicks = 0;
        m_iTimer = m_iMaxTimer;
    }

    // measure time
    MgcReal fCurrentTime = GetTimeInSeconds();
    MgcReal fDelta = fCurrentTime - m_fLastTime;
    m_fLastTime = fCurrentTime;
    m_fAccumulatedTime += fDelta;
}
//---------------------------------------------------------------------------
void MgcApplication::UpdateClicks ()
{
    m_iClicks++;
}
//---------------------------------------------------------------------------
void MgcApplication::DrawFrameRate (int iX, int iY)
{
    if ( --m_iTimer == 0 )
    {
        if ( m_fAccumulatedTime > 0.0 )
            m_fFrameRate = m_iClicks/m_fAccumulatedTime;
        else
            m_fFrameRate = 0.0;

        m_iTimer = m_iMaxTimer;
    }

    char acMessage[256];
    sprintf_s(acMessage,256,"fps: %.1lf",(double)m_fFrameRate);
    ms_spkRenderer->Draw(iX,iY,acMessage);
}
//---------------------------------------------------------------------------
